package com.gzs.learn.springcloud.service;

import jodd.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ThreadPoolExample {

    static ExecutorService POOL_FIXED = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100), new ThreadPoolExecutor.CallerRunsPolicy());
    static ExecutorService POOL_WITH_CUSTOM_FACTORY = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100), buildThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());

    public static void main(String[] args) {
        ExecutorService es = POOL_FIXED;
        try {
            es.submit(() -> doGetOrder());
            CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> doGetUser(), es);
            CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> doGetOrder(), es);

            System.out.println(userFuture.get() + ",");
            Object obj = orderFuture.get();
            System.out.println(obj);
            es.awaitTermination(3, TimeUnit.HOURS);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static ThreadFactory buildThreadFactory() {
        return ThreadFactoryBuilder.create()
                .setUncaughtExceptionHandler((thread, throwable) -> {
                    log.error("thread id {}", thread.getId(), throwable);
                })
                .setNameFormat("test-pool-%s")
                .get();
    }

    public static String doGetUser() {
        long threadId = Thread.currentThread().getId();
        log.info("do get user current threadId {}", threadId);
        return "user";
    }

    public static String doGetOrder() {
        // System.out.println("do get order");
        long threadId = Thread.currentThread().getId();
        log.info("do get order current threadId {}", threadId);
        throw new NullPointerException();
    }

    @Test
    public void testExceptionThrow() throws Exception {
        ExecutorService es = POOL_FIXED;
        es.execute(() -> doGetOrder());
        CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> doGetUser(), es);
        CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> doGetOrder(), es);

        System.out.println(userFuture.get() + ",");
        Object obj = orderFuture.get();
        System.out.println(obj);
        es.awaitTermination(3, TimeUnit.HOURS);
    }

    @Test
    public void testExceptionWitCustomFactoryThrow() throws Exception {
        ExecutorService es = POOL_WITH_CUSTOM_FACTORY;
        es.execute(() -> doGetOrder());
        /*Future<String> f = */es.submit(() -> doGetOrder());
        // f.get();
        es.submit(() -> doGetUser());
        CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> doGetUser(), es);
        CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> doGetOrder(), es);
        System.out.println(userFuture.get() + ",");
        Object obj = orderFuture.get();
        System.out.println(obj);
        es.submit(() -> doGetUser());

        es.awaitTermination(3, TimeUnit.HOURS);
    }
}
